#include "liotool.h"

namespace Lio {

static int _numToStr(int n, STR str, int length, int system, BOOL upper)
{
	if(n<=system)
	{
		str[0]=numToChar(n,upper);
		return 1;
	}
	int count=_numToStr(n/system,str,length,system,upper);
	if(count!=length)
	{
		str[count]=numToChar(n%system,upper);
		return count+1;
	}
	return count;
}
int numToStr(int n, STR str, int length, int system, BOOL upper)
{
	if(!str||!length)
		return 0;
	if(system<2||system>16)
		system=10;
	int count=0;
	if(n<0)
	{
		n=-n;
		str[0]='-';
		str++;
		length--;
	}
	count=_numToStr(n,str,length,system,upper);
	str[count]=0;
	return count;
}
int strToNum(STR str, int length, int system)
{
	if(!str||!length)
		return 0;
	if(system<2||system>16)
		system=10;
	BOOL num=FALSE;
	int digit,n=0,neg=FALSE;
	for(int i=0;i!=length||str[i]!=0;i++)
	{
		digit=charToNum(str[i]);
		if(digit>=0)
		{
			num=TRUE;
			n=system*n+digit;
		}
		else if(num)
			break;
		else if(str[i]=='-')
			neg=num=TRUE;
		else if(str[i]=='+')
			num=TRUE;
	}
	return neg?-n:n;
}

long File::length()
{
	long tmp, size;
	tmp = ftell(file);
	fseek(file, 0L, SEEK_END);
	size = ftell(file);
	fseek(file, tmp, SEEK_SET);
	return size;
}
long File::indexOf(BYTE c, long start)
{
	if(file)
	{
		BYTE byte;
		long index=start,tmp=ftell(file);
		fseek(file, start, SEEK_SET);
		while(fread(&byte,1,1,file))
		{
			if(byte==c)
			{
				fseek(file, tmp, SEEK_SET);
				return index;
				break;
			}
			index++;
		}
		fseek(file, tmp, SEEK_SET);
	}
	return -1;
}
long File::indexOf(const BYTE *block, size_t size, long start)
{
	long result=-1;
	if(file&&block&&size)
	{
		BOOL found=FALSE;
		BYTE byte;
		long index=start,tmp=ftell(file),next=0,i;
		fseek(file, start, SEEK_SET);
		for(;;)
		{
			if(found)
			{
				if(i==(long)size)
				{
					result=index;
					break;
				}
				else if(!fread(&byte,1,1,file))
				{
					break;
				}
				else if(byte!=block[i])
				{
					if(next)
					{
						fseek(file,next-i,SEEK_CUR);
						index+=next;
						next=0;
						i=1;
					}
					else
					{
						index+=i+1;
						found=FALSE;
					}
				}
				else
				{
					if(byte==block[0]&&!next)
						next=i;
					i++;
				}
			}
			else
			{
				if(!fread(&byte,1,1,file))
				{
					break;
				}
				else if(byte==block[0])
				{
					found=TRUE;
					next=0;
					i=1;
				}
				else
				{
					index++;
				}
			}
		}
		fseek(file, tmp, SEEK_SET);
	}
	return result;
}

// CONSTRUCTORS

CSTR NumberFormat::toString(int n, CSTR fmt)
{
	if(!fmt)
	{
		int c=0;
		format[c++]='%';
		if(sign)
		{
			if(sign==' ')
				format[c++]=' ';
			else
				format[c++]='+';
		}
		if(minWidth>0)
		{
			if(zeros)
				format[c++]='0';
			c+=numToStr(minWidth,format+c);
		}
		if(!hexa)
			format[c++]='d';
		else if(uppercase)
			format[c++]='X';
		else
			format[c++]='x';
		format[c]=0;
		fmt=format;
	}
	int count=_sntprintf(string, sizeof(string)-1, fmt, n);
	if(maxWidth>0&&maxWidth<count)
		string[maxWidth]=0;
	return string;
}
CSTR NumberFormat::toString(double n, CSTR fmt)
{
	if(!fmt)
	{
		int c=0;
		format[c++]='%';
		if(sign)
		{
			if(sign==' ')
				format[c++]=' ';
			else
				format[c++]='+';
		}
		if(minWidth>0)
		{
			if(zeros)
				format[c++]='0';
			c+=numToStr(minWidth,format+c);
		}
		if(precision>=0)
		{
			format[c++]='.';
			c+=numToStr(precision,format+c);
		}
		format[c++]='l';
		if(!exposant)
			format[c++]='f';
		else if(uppercase)
			format[c++]='E';
		else
			format[c++]='e';
		format[c]=0;
		fmt=format;
	}
	int count=_sntprintf(string, sizeof(string)-1, fmt, n);
	if(maxWidth>0&&maxWidth<count)
		string[maxWidth]=0;
	return string;
}
int NumberFormat::toInt(CSTR str, int defValue, CSTR fmt)
{
	int c=0,n=defValue;
	if(str&&str[0])
	{
		if(!fmt)
		{
			format[c++]='%';
			if(!hexa)
				format[c++]='d';
			else if(uppercase)
				format[c++]='X';
			else
				format[c++]='x';
			format[c]=0;
			fmt=format;
		}
		_stscanf(str,fmt,&n);
	}
	return n;
}
double NumberFormat::toDouble(CSTR str, double defValue, CSTR fmt)
{
	int c=0;
	double n=defValue;
	if(str&&str[0])
	{
		if(!fmt)
		{
			format[c++]='%';
			format[c++]='l';
			if(!exposant)
				format[c++]='f';
			else if(uppercase)
				format[c++]='E';
			else
				format[c++]='e';
			format[c]=0;
			fmt=format;
		}
		_stscanf(str,fmt,&n);
	}
	return n;
}
void NumberFormat::set(	_TCHAR precision,
						_TCHAR minWidth,
						BOOL exposant,
						_TCHAR sign,
						BOOL zeros,
						BOOL uppercase,
						_TCHAR maxWidth)
{
	this->maxWidth=maxWidth;
	this->minWidth=minWidth;
	this->precision=precision;
	this->hexa=hexa;
	this->exposant=exposant;
	this->sign=sign;
	this->zeros=zeros;
	this->uppercase=uppercase;
}
void NumberFormat::copy(const NumberFormat &model)
{
	minWidth=model.minWidth;
	maxWidth=model.maxWidth;
	precision=model.precision;
	hexa=model.hexa;
	exposant=model.exposant;
	sign=model.sign;
	zeros=model.zeros;
	uppercase=model.uppercase;
}

Mutex::Mutex(LPCTSTR name0, BOOL aquired):hMutex(NULL),name(name0),error(NO_ERROR)
{
	hMutex = CreateMutex(NULL,aquired,name0);
	if(!hMutex) 
		error=GetLastError();
}
Mutex::~Mutex()
{
	if(hMutex)
	{
		ReleaseMutex(hMutex);
		CloseHandle(hMutex);
	}
}
BOOL Mutex::start(DWORD waitTime)
{
	DWORD dwWaitResult=WaitForSingleObject(hMutex,waitTime);
	if(dwWaitResult==WAIT_OBJECT_0) 
	{
		error=NO_ERROR;
		return TRUE;
	}
	else
	{
		error=dwWaitResult;
		return FALSE;
	}
	return TRUE; 
}
BOOL Mutex::stop()
{
	if(ReleaseMutex(hMutex))
	{
		error=NO_ERROR;
		return TRUE;
	}
	else
	{
		error=GetLastError();
		return FALSE;
	}
}
void SetThreadName(LPCSTR name, DWORD threadID)
{
	if(!name||!name[0])
		return;

	struct
	{
		DWORD dwType; // must be 0x1000
		LPCSTR szName; // pointer to name (in user addr space)
		DWORD dwThreadID; // thread ID (-1=caller thread)
		DWORD dwFlags; // reserved for future use, must be zero
	} info = {0x1000, name, threadID, 0};

	__try
	{
		RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (DWORD*)&info );
	}
	__except(EXCEPTION_CONTINUE_EXECUTION)
	{
	}
}

Event::Event(bool bManualReset, char *pEventName)
{
	m_handle = CreateEvent(0, bManualReset, false, pEventName);
}

Event::~Event()
{
	CloseHandle(m_handle);
}

bool Event::IsSignaled() const
{
	return WAIT_OBJECT_0 == ::WaitForSingleObject(m_handle, 0);
}

bool Event::Wait(int timeout) const
{
	return WAIT_OBJECT_0 == ::WaitForSingleObject(m_handle, timeout == -1 ? INFINITE : timeout);
}

void Event::Signal() const
{
	::SetEvent(m_handle);
}

void Event::Reset() const
{
	::ResetEvent(m_handle);
}

}; // namespace Lio
